package cpoo.video;

import java.io.File;

import cpoo.exceptions.MotionException;
import cpoo.globalMotion.MotionVector;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;

import javax.media.Buffer;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;

import cpoo.util.Loger;

public class FindObjectCodec extends PreAccessCodec {
	private Dimension size;
	private AffineTransform[] affineTransform;
	private MotionVector[][] motionVectors;
	private int cols, rows;
	private Rectangle rect;
	private int frameNumber = 0;
	private static final int FRAMES_RANGE = 3;
	private static final double MAX_ANGLE = Math.PI / 2;
	private static final double MIN_AVG_VALUE = 8;
	
	public FindObjectCodec(Dimension size, Rectangle rect, int crRows, int crCols, File movieMotionFile, File movieVectorsFile) {
		this.size = size;
		this.rows = crRows;
		this.cols = crCols;
		this.rect = rect;
		Loger loggerForVectors = new Loger(movieVectorsFile); 
		
		try {
			motionVectors = loggerForVectors.readVectors();
			System.out.println("Wczytano wektory");
		} catch (MotionException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		Loger loggerForMotion = new Loger(movieMotionFile); 
		try {
			affineTransform = loggerForMotion.readAffineTransformations();
			System.out.println("Wczytano przeksztalcenia affiniczne dla ruchu globalnego");
		} catch (MotionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		for (int i=0; i < motionVectors.length; i++){ 
			for(int j = 0; j < motionVectors[i].length; j++) {
				try { 
					affineTransform[i].inverseTransform(motionVectors[i][j].beg, motionVectors[i][j].beg); 
				} catch (NoninvertibleTransformException e){ 
					e.printStackTrace(); 
				} 
			}
		}
		
	}

	protected Image accessFrame(Buffer frame) {
		 
		BufferedImage outImage = null;
		
		BufferToImage stopBuffer = new BufferToImage((VideoFormat) frame.getFormat());
		Image stopImage = stopBuffer.createImage(frame);
	
		outImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
		Graphics og = outImage.getGraphics();
		og.drawImage(stopImage, 0, 0, size.width, size.height, null);
		
		if(frameNumber >= FRAMES_RANGE && frameNumber + FRAMES_RANGE < motionVectors.length) {
			for(int i = 0; i < motionVectors[frameNumber].length; i++) {
				if(testIfObject(frameNumber, i)) {
					paintBlock(outImage, i);
				}
			}
		} 
		
		try {
			Thread.sleep(320);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		if(frameNumber + FRAMES_RANGE < motionVectors.length) {
			paintMovement(outImage, frameNumber);
			frameNumber++;
		}
		
		return outImage;
	}
	
	public boolean testIfObject(int frameNumber, int block) {
		double min = Double.MAX_VALUE;
		double sum = 0;
		
		//sprawdzamy kilka ramek wprzod i wstecz wybierajac sumujac dlugosci wektora oraz
		//sprawdzajac zmiany kata w obrebie tych ramek
		for(int i = frameNumber - FRAMES_RANGE; i < frameNumber + FRAMES_RANGE; i++) {
			double dist = motionVectors[i][block].getLength();
			sum += dist;
			
			double angle = motionVectors[i][block].angle(motionVectors[i + 1][block]);
			if(angle > MAX_ANGLE && angle < 2 * Math.PI - MAX_ANGLE) {
				return false;
			}
		}
		
		//wartosc srednia z kilku sasiednich klatek i porownanie z wartoscia progowa
		double avg = sum / (2 * FRAMES_RANGE + 1);
		
		if (avg < MIN_AVG_VALUE)
			return false;
		
		System.out.println("Avarage[" + block + "] = " + avg);
		System.out.println("Blok nalezy do obiektu!!!");
		return true;
	}
	
	private void paintBlock(BufferedImage image, int blockIndex) {
		int row = blockIndex / cols;
		int col = blockIndex % cols; 
		
		int pixelCol = rect.width / cols;
		int pixelRow = rect.height / rows;
		
		Graphics g = image.getGraphics();
		g.setColor(Color.RED);
		g.drawRect(col * pixelCol, row * pixelRow, pixelCol, pixelRow);
	}
	
	private void paintMovement(BufferedImage image, int frameNumber){
		Graphics g = image.getGraphics();
		g.setColor(Color.WHITE);
		for (int i = 0; i < motionVectors[frameNumber].length; i++){
			Point o = motionVectors[frameNumber][i].beg;
			Point t = motionVectors[frameNumber][i].end;
			g.drawLine(o.x, o.y, t.x, t.y);
		}
	}
}
